      // BitmapMenu.cpp

#include "StdAfx.h"

#include "AnsiEditor.h"
#include "BitmapMenu.h"
#include "resource.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[ ]=__FILE__;
#define new DEBUG_NEW
#endif

#define  BITMAP_WIDTH		16
#define  BITMAP_HEIGHT		16
#define  SEPARATOR_HEIGHT	10

// Construction / Destruction
CBitmapMenu::CBitmapMenu()
{
	OnSysColorChange();
	m_bShowAccelerator = TRUE;
}


CBitmapMenu::~CBitmapMenu()
{
}


void CBitmapMenu::Initialize(UINT uMennID, CWnd *pParent)
{
	LoadMenu(uMennID);
	// Replace menu
	if(pParent != NULL)
	{  
		CMenu *pmenuOld = pParent->GetMenu();
		pParent->SetMenu(this);
		
		if(pmenuOld)
		{
			pmenuOld->DestroyMenu();
		}
	}
}

UINT CBitmapMenu::AddBitmaps(CItemBitmap *pib, UINT uCount)
{ 
	for(UINT uI = 0; uI < uCount; uI++, pib++)
	{  
		m_mapBitmaps.SetAt(pib->m_nID, pib);
	}
	return uCount;
}

UINT CBitmapMenu::RemoveBitmaps(CItemBitmap *pib, UINT uCount)
{  
	for(UINT uI = 0; uI < uCount; uI++, pib++)
	{ 
		m_mapBitmaps.RemoveKey(pib->m_nID);
	}
	return  uCount;
}

void CBitmapMenu::MeasureItem(LPMEASUREITEMSTRUCT lpmis)
{  
	HMENU hmenu = (HMENU)lpmis->itemData;

	UINT uState =::GetMenuState(hmenu, lpmis->itemID, MF_BYCOMMAND);
	if((uState & MF_SEPARATOR) && !(uState & MF_POPUP))
	{
		if((uState & MF_POPUP))
		{
			CString strText;
			::GetMenuString(hmenu, lpmis->itemID, strText.GetBuffer(100), 100, MF_BYCOMMAND);
			strText.ReleaseBuffer();

			AfxMessageBox("!");
		}
		ASSERT(!(uState & MF_POPUP));
		lpmis->itemWidth = BITMAP_WIDTH + 10;
		lpmis->itemHeight = SEPARATOR_HEIGHT;
		return;
	}
	
	CWnd *pWnd = AfxGetMainWnd();
	CDC *pDC = pWnd->GetDC();
	
	MENUDRAWINGINFO mdi;
	ReloadSysInfo(&mdi);
	
	CFont *pOldFont = pDC->SelectObject(&mdi.font);
	
	CString strText;
	::GetMenuString(hmenu, lpmis->itemID, strText.GetBuffer(100), 100, MF_BYCOMMAND);
	strText.ReleaseBuffer();
	
	CRect rect(0, 0, 0, 0);
//	int nI = strText.Find(_T('\t')), nMax = strText.GetLength();
//	if(nI == -1)
//	{
//		nI = nMax;
//	}
	
	pDC->DrawText(strText, &rect, DT_SINGLELINE|DT_CALCRECT);

	if(m_bShowAccelerator)
	{
		CommandInfoEx CmdInfoEx;
		if(gCommandMap.Lookup(lpmis->itemID, CmdInfoEx))
		{  
			CRect rect2(0, 0, 0, 0);
			pDC->DrawText(CmdInfoEx.sAccelerator, &rect2, DT_SINGLELINE|DT_CALCRECT);
			
			rect.right += rect2.right + 30;
			rect.bottom = max(rect.bottom, rect2.bottom);
		}
	}
	else
	{
		rect.right += 3;
	}
	
	if(uState & MF_POPUP)
	{
		rect.right += 20;
	}
	
	pDC->SelectObject(pOldFont);
	pWnd->ReleaseDC(pDC);
	
	// Text width & height
	lpmis->itemWidth = rect.Width() + BITMAP_WIDTH + 16;
	lpmis->itemHeight = ((max(rect.Height() + 2, BITMAP_HEIGHT + 4) + 1) & 0xFFFE);
}


void CBitmapMenu::ReloadSysInfo(LPMENUDRAWINGINFO pmdi, BOOL bFontBold /* = FALSE */) const
{  
	// Foreground & background colors
	pmdi->crHighlight = GetSysColor(COLOR_HIGHLIGHT);
	pmdi->crBackColor = GetSysColor(COLOR_MENU);
	pmdi->crText = GetSysColor(COLOR_MENUTEXT);
	pmdi->crDisabled = GetSysColor(COLOR_GRAYTEXT);
	
	// Get the menu dimensions
	ZeroMemory(&pmdi->ncm, sizeof(NONCLIENTMETRICS));
	pmdi->ncm.cbSize = sizeof(NONCLIENTMETRICS);
	
	SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, (void *) &pmdi->ncm, FALSE);
	
	// Menu check mark dimensions
	pmdi->lDims = GetMenuCheckMarkDimensions();
	
	// Recreate font
	BOOL bRecreatefont = TRUE;
	
	if(pmdi->font.m_hObject)
	{  
		LOGFONT lf;
		pmdi->font.GetLogFont(&lf);
		if(!memcmp(&lf, &pmdi->ncm.lfMenuFont, sizeof(LOGFONT) - LF_FACESIZE) &&
		   !_tcscmp(lf.lfFaceName, pmdi->ncm.lfMenuFont.lfFaceName))
			bRecreatefont = FALSE;
	}
	
	if(bRecreatefont)
	{
		pmdi->font.DeleteObject();
		if(bFontBold)
		{
			pmdi->ncm.lfMenuFont.lfWeight = FW_BOLD;
		}
		pmdi->font.CreateFontIndirect(&pmdi->ncm.lfMenuFont);
	}
}


void CBitmapMenu::Synchronize(CMenu *pMenu)
{  
	// Set menu popups, items & separators to be owner-drawn
	MENUITEMINFO mii;
	mii.cbSize = sizeof(MENUITEMINFO);
	mii.fMask = (MIIM_STATE | MIIM_DATA | 0x100);  // MIIM_FTYPE;
	
	for(int nI = 0, nCount = pMenu->GetMenuItemCount(); nI < nCount; nI++)
	{  
		UINT uState = pMenu->GetMenuState(nI, MF_BYPOSITION);
	
		// Is it popup or separator ?
		if(uState & (MF_POPUP | MF_SEPARATOR))
		{  
			VERIFY(pMenu->GetMenuItemInfo(nI, &mii, TRUE));
			mii.fType |= MFT_OWNERDRAW;
			mii.dwItemData = (DWORD) pMenu->m_hMenu;
			
			VERIFY(::SetMenuItemInfo(pMenu->m_hMenu, nI, TRUE, &mii));
		}
		// Yeah, it's a menu item
		else
		{  
			UINT nID = pMenu->GetMenuItemID(nI);
		
			VERIFY(pMenu->GetMenuItemInfo(nID, &mii));

//			mii.fType &= ~MFT_OWNERDRAW;
//			::SetMenuItemInfo(pMenu->m_hMenu, nID, FALSE, &mii);

			mii.fType |= MFT_OWNERDRAW;
			mii.dwItemData = (DWORD) pMenu->m_hMenu;
			
			VERIFY(::SetMenuItemInfo(pMenu->m_hMenu, nID, FALSE, &mii));
		}
	}
}


// Class CItemBitmap
CBitmapMenu::CItemBitmap::CItemBitmap(UINT nID, CImageList *pil, UINT nPos)
{  
	m_nID = nID;
	m_pil = pil;
	m_nPos = nPos;
}

CBitmapMenu::CItemBitmap::~CItemBitmap()
{
}

void CBitmapMenu::DrawItem(LPDRAWITEMSTRUCT lpdis)
{  
//	BOOL bFlag = FALSE;	//del
	HMENU hMenu = (HMENU)lpdis->hwndItem;
	UINT uState =::GetMenuState(hMenu, lpdis->itemID, MF_BYCOMMAND);

	MENUDRAWINGINFO mdi;
	ReloadSysInfo(&mdi, (::GetMenuDefaultItem(hMenu, FALSE, 0) == lpdis->itemID));
	
	int cx = lpdis->rcItem.right - lpdis->rcItem.left;
	int cy = lpdis->rcItem.bottom - lpdis->rcItem.top;
	CRect rect(0, 0, cx, cy);
	
	CDC *pDC = CDC::FromHandle(lpdis->hDC);
	
	CDC dcMem;
	CBitmap bmp;
	dcMem.CreateCompatibleDC(pDC);
	bmp.CreateCompatibleBitmap(pDC, cx, cy);
	CBitmap *pOldBitmap = (CBitmap*)dcMem.SelectObject(&bmp);

	dcMem.FillSolidRect(rect, mdi.crBackColor);
	
	long lWidthHeight = BITMAP_WIDTH + 4;
	rect.left = lWidthHeight + 4;
	
	BOOL bSeparator = ((uState & MF_SEPARATOR) && !(uState & MF_POPUP));
	if(bSeparator)
	{
		CRect rc(2, (SEPARATOR_HEIGHT >> 1) - 1, rect.right - 2, SEPARATOR_HEIGHT >> 1);
		dcMem.DrawEdge(&rc, EDGE_ETCHED, BF_TOP);
	}
	else	
	{
	//////////////////////////////////////////////////////////////////////////

	COLORREF crHilight = GetSysColor(COLOR_3DHILIGHT);
	COLORREF crShadow = GetSysColor(COLOR_3DSHADOW);

	COLORREF crText;
	BOOL bGrayed = (lpdis->itemState & ODS_GRAYED);
	BOOL bSelected = (lpdis->itemState & ODS_SELECTED);
	BOOL bChecked = (lpdis->itemState & ODS_CHECKED);
	BOOL bRadio = FALSE;
	if(bChecked)
	{
		MENUITEMINFO mii;
		mii.cbSize = sizeof(MENUITEMINFO);
		mii.fMask = MIIM_CHECKMARKS;
		::GetMenuItemInfo(hMenu, lpdis->itemID, FALSE, &mii);
		if(mii.hbmpChecked)
		{
			bRadio = TRUE;
		}
	}

	CItemBitmap *pib = NULL;
	CImageList *pil = NULL;
	UINT uPosImage = 0;

	if(m_mapBitmaps.Lookup(lpdis->itemID, pib))
	{
		pil = pib->m_pil;
		uPosImage = pib->m_nPos;
	}
	else if(bChecked)
	{
		if(!bRadio)
		{
			m_mapBitmaps.Lookup((UINT)-1, pib);
			pil = pib->m_pil;
			uPosImage = pib->m_nPos;
		}
	}

	// Hilite rectangle or not
	if(bSelected && (lpdis->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)))
	{  
		CRect rectHilite(pil? (lWidthHeight + 1): 0, 0, cx, cy);
		dcMem.FillSolidRect(rectHilite, mdi.crHighlight);
		crText = bGrayed ? mdi.crDisabled : (mdi.crText ^ 0xFFFFFF);
	}
	else
	{  
		crText = bGrayed ? mdi.crDisabled : mdi.crText;
	}
	
	// Draw 3D rectangle and bitmap if need so
	if(pil)
	{  
		POINT pt = { ((lWidthHeight - BITMAP_WIDTH) >> 1), (cy - BITMAP_HEIGHT) >> 1 };
		if(!bGrayed)
		{  
			COLORREF crlt;
			COLORREF crrb;
			
			if(bChecked)
			{
				crlt = crShadow;
				crrb = crHilight;

				CDC dcxx;
				dcxx.CreateCompatibleDC(pDC);
				CBitmap *pOldBitmap = dcxx.SelectObject(&m_bmpxx);

				if(pib->m_nID == -1)
				{
					if(!bSelected)
					{
						dcMem.BitBlt(pt.x + 1, pt.y + 1, 13, 13, &dcxx, 0, 0, SRCCOPY);
					}
					dcMem.Draw3dRect(pt.x, pt.y, 15, 15, crShadow, crHilight);
				}
				else
				{
					if(!bSelected)
					{
						dcMem.BitBlt(pt.x - 1, pt.y - 1, 18, 18, &dcxx, 0, 0, SRCCOPY);
					}
					dcMem.Draw3dRect(0, (cy - lWidthHeight) >> 1, lWidthHeight, lWidthHeight, crlt, crrb);
					++pt.x;
					++pt.y;
				}

				dcxx.SelectObject(pOldBitmap);
			} // end if(bChecked)
			else if(bSelected)
			{
				crlt = crHilight;
				crrb = crShadow;
				dcMem.Draw3dRect(0, (cy - lWidthHeight) >> 1, lWidthHeight, lWidthHeight, crlt, crrb);
			}

			pil->Draw(&dcMem, uPosImage, pt, ILD_TRANSPARENT);
		} // end if(!bGrayed)
		else
		{
			HICON hIcon = pil->ExtractIcon(uPosImage);
			::DrawState(dcMem.GetSafeHdc(), NULL, NULL, (LPARAM)hIcon, 0, pt.x, pt.y, 
						BITMAP_WIDTH, BITMAP_HEIGHT, DST_ICON|DSS_DISABLED);
			DestroyIcon(hIcon);
		}
	}
	else if(bRadio)
	{
		POINT pt = { ((lWidthHeight - BITMAP_WIDTH) >> 1) + 6, ((cy - BITMAP_HEIGHT) >> 1) + 5};
		CRect rect(pt, CSize(6, 6));
		COLORREF color;
		if(bGrayed)
		{
			if(!bSelected)
			{
				color = GetSysColor(COLOR_BTNHIGHLIGHT);
				dcMem.FillSolidRect(CRect(rect.left + 2, rect.top + 1, rect.right, rect.bottom + 1), color);
				dcMem.FillSolidRect(CRect(rect.left + 1, rect.top + 2, rect.right + 1, rect.bottom), color);
			}
			color = GetSysColor(COLOR_GRAYTEXT);
		}
		else
		{
			color = GetSysColor(bSelected? COLOR_HIGHLIGHTTEXT: COLOR_MENUTEXT);
		}
		dcMem.FillSolidRect(CRect(rect.left + 1, rect.top, rect.right - 1, rect.bottom), color);
		dcMem.FillSolidRect(CRect(rect.left, rect.top + 1, rect.right, rect.bottom - 1), color);

	}
	
	// Draw text
	dcMem.SetBkMode(TRANSPARENT);
	
	// Create a font based on menu metrics
	CFont *pOldFont = NULL;
	
//	UINT nDefID = ::GetMenuDefaultItem(hMenu, FALSE, 0);
//	if(nDefID == lpdis->itemID)
//	{
////		afxDump << "!";
////		mdi.font.setbol
//	}
//	else
//	{
	pOldFont = (CFont *) dcMem.SelectObject(&mdi.font);
//	}
	
	// Draw text
	CString strText;
	::GetMenuString(hMenu, lpdis->itemID, strText.GetBuffer(100), 100, MF_BYCOMMAND);
	strText.ReleaseBuffer();
	
	UINT uFormat = DT_SINGLELINE|DT_VCENTER;
	if(lpdis->itemState & ODS_NOACCEL)
	{
		uFormat |= DT_HIDEPREFIX;
	}

	if(bGrayed && !bSelected)
	{  
		CRect rectShifted = rect;
		rectShifted.InflateRect(-1, -1, 1, 1);
		
		dcMem.SetTextColor(GetSysColor(COLOR_BTNHIGHLIGHT));
		dcMem.DrawText(strText, &rectShifted, uFormat|DT_LEFT);
	}
	
	dcMem.SetTextColor(crText);
//	afxDump << rect << "\n";
	dcMem.DrawText(strText, &rect, uFormat|DT_LEFT);
	
	// Draw accelerator keys text
	if(m_bShowAccelerator)
	{
		CommandInfoEx CmdInfoEx;
		if(gCommandMap.Lookup(lpdis->itemID, CmdInfoEx))
		{  
			rect.right -= (lWidthHeight + 0);
		
	//		CRect rect2(0, 0, 0, 0);
	//		pDC->DrawText(CmdInfoEx.sAccelerator, &rect2, DT_SINGLELINE|DT_CALCRECT);
	//		
	//		rect.right += rect2.right + 30;
	//		rect.bottom = max(rect.bottom, rect2.bottom);
	//	}		
	//		TCHAR *szText = strText.GetBuffer(nMax + 1) + nI;
	//		nMax -= nI;
			
			if(bGrayed && !bSelected)
			{  
				CRect rectShifted = rect;
				rectShifted.InflateRect(-1, -1, 1, 1);
				
				dcMem.SetTextColor(GetSysColor(COLOR_BTNHIGHLIGHT));
				dcMem.DrawText(CmdInfoEx.sAccelerator, &rectShifted, uFormat|DT_RIGHT);
				
				// Restore color
				dcMem.SetTextColor(crText);
			}
			
			dcMem.DrawText(CmdInfoEx.sAccelerator, &rect, uFormat|DT_RIGHT);
			
	//		strText.ReleaseBuffer();
		}
	}
	
	dcMem.SelectObject(pOldFont);

	//////////////////////////////////////////////////////////////////////////
	}

	pDC->BitBlt(lpdis->rcItem.left, lpdis->rcItem.top, cx, cy, &dcMem, 0, 0, SRCCOPY);

	// Resotre graphic objects
	dcMem.SelectObject(pOldBitmap);
}

void CBitmapMenu::OnSysColorChange()
{
	COLORMAP colormap[] = { { RGB(0, 0, 0), GetSysColor(COLOR_BTNFACE) },
							{ RGB(255, 255, 255), GetSysColor(COLOR_BTNHILIGHT)}};
	m_bmpxx.DeleteObject();
	m_bmpxx.LoadMappedBitmap(IDB_BITMAP_XX, 0, colormap, 2);
}
